package net.bingosoft.common.struts;

import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Method;
import java.net.URLEncoder;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import net.bingosoft.common.BeanHelper;
import net.bingosoft.common.ObjectRegistry;
import net.bingosoft.common.config.Config;
import net.bingosoft.common.exception.BusinessException;
import net.bingosoft.common.util.FileHelper;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.ActionServlet;
import org.apache.struts.actions.MappingDispatchAction;
import org.apache.struts.upload.FormFile;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
/**
 * 2007-8-7 下午05:33:47
 * Author:yangdongyu(yangdy@bingosoft.net)
 * ReadMe:Action 的基类,提供和Spring的集成、对MappingDispatchAction的支持和对业务异常的处理及一些通用的方法
 * ChangeLog:Ver:1.6
 */
public abstract class BaseAction extends MappingDispatchAction {
	protected final Log log = LogFactory.getLog(this.getClass());
	/**
	 * Struts 的主调用方法,在此进行了扩展,并添加一个沙盒
	 * 
	 * @param mapping
	 * @param form
	 * @param request
	 * @param response
	 * @return ActionForward
	 * @throws Exception 
	 */
	public final ActionForward execute(ActionMapping mapping, ActionForm actionForm,
			HttpServletRequest request, HttpServletResponse response) throws Exception {
		log.debug(">>>>>>>>>>>>>>>> 请求URI: " + request.getRequestURI());
		//get dispath method name
		String methodName = mapping.getParameter();
		//权限验证
		if(!canExecute(request,methodName)){
			throw new UnsupportedOperationException("无法执行对应的操作,页面已过期或者您没有对应的权限 ...");
		}
		ActionForward forward = null;
		try{
			long start = beforeExecute(request, response,methodName);
			if(isCancelled(request))
			{
				ActionForward af = cancelled(mapping, actionForm, request, response);
				if(af != null)
					return af;
			}
			if("execute".equals(methodName) || "perform".equals(methodName)){
				String message = messages.getMessage("dispatch.recursive", mapping.getPath());
				log.error(message);
				throw new ServletException(message);
			} else{				
//				if(log.isDebugEnabled()){
//					Object dataToShow = actionForm;
//					if(actionForm instanceof LazyValidatorForm){
//						dataToShow = ((LazyValidatorForm)actionForm).getMap();
//					}
//					log.debug("ActionForm Data:" + JSONConverter.toJSON(dataToShow,null,"servletWrapper","resultValueMap","validatorResults"));	
//				}
				forward = dispatchMethod(mapping, actionForm, request, response, methodName);
			}
			long end = afterExecute(request, response,methodName);
			log.debug("Out off " + this.getClass().getSimpleName() + "." + methodName +  ",excuting finished in " + (end - start) + " ms ..." );
		}catch(Exception ex){
			forward = onException(mapping, actionForm, request, response,ex);
		}
		return forward;
	}

	/**
	 * 执行主方法之前调用的方法
	 * @param request
	 * @param response
	 * @param methodName 调用方法的名称
	 */
	protected long beforeExecute(HttpServletRequest request, HttpServletResponse response,String methodName){
		log.debug("Enter into method " + this.getClass().getSimpleName() + "." + methodName + " ...");
		return System.currentTimeMillis();
	}
	/**
	 * 方法执行之后调用的方法
	 * @param request
	 * @param response
	 * @param methodName 调用方法的名称
	 */
	protected long afterExecute(HttpServletRequest request, HttpServletResponse response,String methodName){
		if(isSyn())saveToken(request);
		return System.currentTimeMillis();
	}
	/**
	 * 发生异常时候的处理方法,在此对业务异常进行了处理
	 * @param ex
	 * @throws Exception 
	 */
	protected ActionForward onException(ActionMapping mapping, ActionForm actionForm,
			HttpServletRequest request, HttpServletResponse response,Exception ex) throws Exception{
		if(ex instanceof BusinessException){
			BusinessException businessException = (BusinessException)ex;
			String code = businessException.getCode();
			if(StringUtils.isNotEmpty(code)){
				String error = getErrorMessage(request, code);
				if(StringUtils.isNotEmpty(error)){
					businessException.setLocalizedMessage(error  + "["+code+"]");
				}
			}
		}
		log.debug("Exception occured in " + this.getClass().getSimpleName(),ex);
		throw ex;
	}
	/**
	 * 检查是否可以执行
	 * @param request
	 * @return
	 */
	protected boolean canExecute(HttpServletRequest request,String method){
		return (!isSyn() || isTokenValid(request,true)) ;
	}
	/**
	 * 是否使用同步令牌的标志
	 * 
	 * @return 返回true为使用
	 */
	protected boolean isSyn() {
		return false;
	}
	/**
	 * 覆盖该方法,自动实现service的自动装配
	 */
	public void setServlet(ActionServlet actionServlet) {
		super.setServlet(actionServlet);
		if (actionServlet != null && Config.getBoolean("AUTOWIRE_ACTION_SERVICE",true)) {
			try{
				log.debug("尝试为Action装配service ...");
				ObjectRegistry.getApplicationContext()
					.getAutowireCapableBeanFactory()
					.autowireBeanProperties(this, AutowireCapableBeanFactory.AUTOWIRE_BY_NAME, false);
				log.debug("Action装配service成功 ...");
			}catch(Exception e){
				log.error("通过service的名称为Action自动装配service时发生异常...",e);
			}
		}
	}

	/**
	 * 
	 * @param mapping
	 * @param form
	 * @param request
	 * @param response
	 * @return
	 */
	protected ActionForward doExecute(ActionMapping mapping, ActionForm actionForm,
			HttpServletRequest request, HttpServletResponse response) throws Exception{return null;}
	/**
	 * 获取bean
	 * @param beanID
	 * @return
	 */
	protected <T>T getBean(String beanID,Class<T> type){
		return ObjectRegistry.getBean(beanID,type);
	}
 
	/**
	 * 转向成功提示页面
	 *
	 * @param successInfo 成功提示信息
	 * @param returnPath  提示页面返回地址
	 * @param request
	 * @return ActionForward 对象
	 */
	protected ActionForward turnToSuccess(String successInfo,
			String returnPath, HttpServletRequest request,ActionMapping mapping) {
		request.setAttribute("MESSAGE", successInfo);
		request.setAttribute("RETURN_PATH", returnPath);
		return mapping.findForward("success");
	}
    /**
     * 从request中获取请求参数，并以Map的形式返回
     * @param request
     * @return
     */
	public Map getParameterMap(HttpServletRequest request) {
		Enumeration names = request.getParameterNames();
		Map<String,Object> map = new HashMap<String,Object>();
		while (names.hasMoreElements()) {
			String name = (String) names.nextElement();
			String[] s = request.getParameterValues(name);
			if (s != null) {
				if (s.length > 1) {
					map.put(name, s);
				}else{
					map.put(name, s[0]);
				}
			}
		}
		return map;
	}
	/**
	 * 转向成功提示页面
	 *
	 * @param successInfo 成功提示信息
	 * @param returnPath  提示页面返回地址
	 * @param request
	 * @return ActionForward 对象
	 */
	protected ActionForward turnToSuccess(String successInfo,
			String returnPath,String script, String contextPath,HttpServletRequest request,HttpServletResponse response) {
		StringBuilder html = new StringBuilder("<script>");
		if(StringUtils.isNotEmpty(successInfo)){
			html.append("alert('"+successInfo+"');");
		}
		if(StringUtils.isNotEmpty(script)){
			html.append(script);
		}else if(StringUtils.isNotEmpty(returnPath)){
			html.append("window.location = '").append(StringUtils.isEmpty(contextPath)?request.getContextPath():contextPath).append(returnPath).append("';");
		}
		html.append("</script>");		
		renderHtml(response,html.toString());
		return null;
	}
	/**
	 * 转向成功提示页面
	 *
	 * @param successInfo 成功提示信息
	 * @param returnPath  提示页面返回地址
	 * @param request
	 * @return ActionForward 对象
	 */
	protected ActionForward turnToSuccess(String successInfo,String returnPath,ActionMapping mapping,HttpServletRequest request,HttpServletResponse response) {
		StringBuilder html = new StringBuilder("<script>");
		if(StringUtils.isNotEmpty(successInfo)){
			html.append("alert('"+successInfo+"');");
		}
		returnPath = (StringUtils.isEmpty(returnPath)) ? mapping.findForward("success").getPath() : returnPath;
		html.append("window.location = '").append(request.getContextPath()).append(returnPath).append("';");
		html.append("</script>");		
		renderHtml(response,html.toString());
		return null;
	}
	/**
	 * 转向成功提示页面
	 *
	 * @param successInfo 成功提示信息
	 * @param returnPath  提示页面返回地址
	 * @param request
	 * @return ActionForward 对象
	 */
	protected ActionForward turnToSuccess(String contextPath,String successInfo,
			String returnPath, HttpServletRequest request,ActionMapping mapping) {
		request.setAttribute("MESSAGE", successInfo);
		request.setAttribute("RETURN_PATH", returnPath);
		request.setAttribute("CONTEXT_PATH", contextPath);
		return mapping.findForward("success");
	}

	/**
	 * 从form中抽取查询字符串
	 * !!!!! 注意调用该方法之后,form中的属性将会被置空,
	 * 请在调用前保存可能要用到的相关数据
	 * @param form ActionForm
	 * @return 查询字符串
	 */
	protected String getQueryString(ActionForm form){
		return getQueryString(form,true);
	}
	/**
	 * 从form中抽取查询字符串
	 * @param form ActionForm
	 * @param deReset 调用该方法后是否清空form 
	 * @return 查询字符串
	 */
	protected String getQueryString(ActionForm form, boolean doReset){
		StringBuffer buffer = new StringBuffer();
		String result = "";
		try {
			BeanInfo bi = Introspector.getBeanInfo(form.getClass(),ActionForm.class);
			PropertyDescriptor[] pds = bi.getPropertyDescriptors();
			for(int i=0; i<pds.length;i++){
				String name = pds[i].getName();
				Method reader = pds[i].getReadMethod();
				if(reader == null) continue;
				Object obj = reader.invoke(form,new Object[]{});
				if (obj != null && StringUtils.isNotEmpty(String.valueOf(obj))){
					String value = String.valueOf(obj);
					buffer.append("&").append(name).append("=").append(URLEncoder.encode(value,"UTF-8"));
					Method writer = pds[i].getWriteMethod();
					if(writer == null) continue;
					if(doReset)
						pds[i].getWriteMethod().invoke(form,new Object[]{null});//do reset
				}
			}
			if(buffer.length() > 0){
				result = "?" + buffer.toString().substring(1);
			}
			log.debug("QueryString : " + result);
		} catch (Exception e) {
			log.error("从form中抽取查询条件时出错",e);
		}
		return result;
	}

	/**
	 * 根据错误代码获取对应在资源文件中定义的错误消息
	 * @param request
	 * @param errorCode 错误代码
	 * @return
	 */
	protected String getErrorMessage(HttpServletRequest request,String errorCode){
		return getStrutsMessage(request,"errorCode",errorCode);
	}
	/**
	 * 
	 * @param request 
	 * @param bundelKey 消息文件在Struts-config.xml 文件中对应的key值
	 * @param errorCode 消息的键值
	 * @param args 消息参数
	 * @return
	 */
	protected String getStrutsMessage(HttpServletRequest request,String bundelKey,String errorCode,String ...args){
		return getResources(request, bundelKey).getMessage(errorCode,args);
	}
	/**
	 * 转向成功页面
	 * @param mapping
	 * @return
	 */
	protected ActionForward forwardToSuccess(ActionMapping mapping){
		return mapping.findForward("success");
	}
	@Override
	protected ActionForward unspecified(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
		log.debug("No dispath method specified , call default method doExecute ...");
		return doExecute(mapping, form, request, response);
	}

	/**
	 * 上传文件file 到服务器的指定目录 dir
	 * @param file 待上传的文件
	 * @param dir 文件的存放目录
	 * @return 文件在服务器上的最终保存位置
	 * @throws FileNotFoundException
	 * @throws IOException
	 */
	protected String uploadFile(FormFile file,String dir) throws FileNotFoundException, IOException{
		if(file== null || StringUtils.isEmpty(file.getFileName())){
			log.warn("没有要上传的文件...");
			return "";
		}
		String fileName = file.getFileName();
		log.debug("上传文件的名称为 : " + fileName);
		//上传文件默认根目录,在Web应用根目录下的upload目录下
		String defaultRoot = FileHelper.replace(servlet.getServletContext().getRealPath("/upload"),"\\","/");
		//上传文件的根目录
		String upLoadRootDir = Config.getString("UPLOAD_ROOT_DIR",defaultRoot);
		//文件的存放目录
		String targetDir = upLoadRootDir +  (StringUtils.isEmpty(dir)?"":dir);    
		//生成文件名称
		String uniqueFileName = FileHelper.generateUniqueFileName(fileName);
		String finalFileName = (targetDir.endsWith("/") ? targetDir : targetDir+"/") + uniqueFileName;
		log.debug("文件上传位置:" + finalFileName);
		//创建文件
		FileHelper.createFile(finalFileName, file.getInputStream()); 
		log.debug("文件上传成功");
		return finalFileName;
	}
	
	/**
	 * 直接输出.
	 * 
	 * @param contentType 内容的类型.html,text,xml的值见后，json为"text/x-json;charset=UTF-8"
	 */
	protected void render(HttpServletResponse response, String text,String contentType){
		try {
			response.setContentType(contentType);
			response.getWriter().write(text);
		} catch (IOException e) {
			log.error(e.getMessage(), e);
		}
	}

	/**
	 * 直接输出JSON对象.
	 */
	protected void renderJSON(HttpServletResponse response, String text) {
		render(response,text,"text/x-json;charset=UTF-8");
	}
	/**
	 * 直接输出纯字符串.
	 */
	protected void renderText(HttpServletResponse response, String text) {
		render(response,text,"text/plain;charset=UTF-8");
	}

	/**
	 * 直接输出纯HTML.
	 */
	protected void renderHtml(HttpServletResponse response, String text) {
		log.debug("输出的text/html的内容为: " + text);
		render(response,text,"text/html;charset=UTF-8");
	}

	/**
	 * 直接输出纯XML.
	 */
	protected void renderXML(HttpServletResponse response, String text) {
		render(response,text,"text/xml;charset=UTF-8");
	}
	
    /**
     * 在request对象中取出int类型的参数值
     * @param request
     * @param param  参数名字
     * @return 如果参数不存在或者不能转换为int类型则返回0，否则返回实际数值
     */
	protected int getIntParam(HttpServletRequest request, String param) {
        int value = 0;
        try {
            value = Integer.parseInt(request.getParameter(param).trim());
        } catch (Exception e) {
            log.debug(e);
        }
        return value;
    }
    /**
     * 获取一个boolean类型的参数
     * @param request
     * @param param
     * @return
     */
	protected boolean getBooleanParam(HttpServletRequest request, String param){
    	return Boolean.valueOf(getStringParam(request, param)).booleanValue();
    }
    
    /**
     * 在request对象中取出int类型的参数值,如果出现异常，则返回默认值nDefaultVal
     * @param request
     * @param param  参数名字
     * @return 如果参数不存在或者不能转换为int类型则返回0，否则返回实际数值
     */
	protected int getIntParam(HttpServletRequest request, String param, int nDefaultVal) {
        int value = nDefaultVal;
        log.info( String.valueOf(nDefaultVal) );
        try {
            value = Integer.parseInt(request.getParameter(param).trim());
        } catch (Exception e) {
            log.debug(e);
        }
        return value;
    }

    /**
     * 在request对象中取出long类型的参数值
     * @param request
     * @param param 参数名字
     * @return 如果参数不存在或者不能转换为long类型则返回0，否则返回实际数值
     */
	protected long getLongParam(HttpServletRequest request, String param) {
        long value = 0;
        try {
            value = Long.parseLong(request.getParameter(param));
        } catch (Exception e) {
            log.debug(e);
        }
        return value;
    }
    
    /**
     * 在request对象中取出非null的字符串参数值
     * @param request
     * @param param
     * @return 如果参数不存在返回""，否则返回实际字符串
     */
	protected static String getStringParam(HttpServletRequest request, String param) {
        String value = request.getParameter(param);
        return (null == value) ?"": value ;
    }
    /**
     * 从request对象中取出param指定的参数,如果不存在,返回defaultValue
     * @param request
     * @param param
     * @param defaultValue
     * @return
     */
	protected static String getStringParam(HttpServletRequest request, String param,String defaultValue){
    	String value = request.getParameter(param);
        return (null == value) ?defaultValue: value ;
    }
    /**
     * 根据cookie名称获取对应的Cookie
     * @param request
     * @param cookieName
     * @return
     */
	protected static Cookie getCookieByName(HttpServletRequest request,String cookieName){
        Cookie cookie = null;        
        Cookie[] cookies = request.getCookies();
        if(null != cookies){
            for(int i=0;i<cookies.length;i++){
                if(cookies[i].getName().equalsIgnoreCase(cookieName)){
                    cookie = cookies[i];
                    break;
                }
            }
        }
        return cookie;
    }    

    /**
     * 给链接URL添加参数
     * @param URL
     * @param paramName
     * @param paramValue
     * @return
     */
	protected static String appendParamToURI(String URL,String paramName,String paramValue){
    	String appendedURI = URL;
    	
    	if(null != appendedURI){
    		if(appendedURI.indexOf("?") < 0){
    			appendedURI += "?";
    		}else{
    			appendedURI += "&";
    		}
        	appendedURI += ( paramName + "=" + paramValue);    		
    	}
    	
    	return appendedURI;
    }
    
    /**
     * 保存分页查询结果
     * @param resultList
     * @param request
     */
    protected void saveQueryResult(HttpServletRequest request,List resultList){
    	request.setAttribute("ResultList", resultList);
    }
    /**
     * 保存分页查询结果
     * @param resultList
     * @param request
     * @param gridId 结果集放在request中的键值
     */
    protected void saveQueryResult(HttpServletRequest request,List resultList,String resultKey){
    	request.setAttribute(resultKey, resultList);
    }
    /**
	 * 获取浏览器提交的同名整型参数
	 * 
	 * @param request
	 * @param paramName
	 * @param defaultNum
	 * @return int[]
	 */
    protected static int[] getIntParameters(HttpServletRequest request, String paramName,int defaultNum) {
		String[] paramValues = request.getParameterValues(paramName);
		if (paramValues == null) {
			return null;
		}
		int[] values = new int[paramValues.length];
		for (int i = 0; i < paramValues.length; i++) 	
			values[i] = BeanHelper.getInt(paramValues[i], defaultNum);
		
		return values;
	}

	/**
	 * 获取浏览器提交的同名字符串类型参数
	 * 
	 * @param request
	 * @param paramName
	 * @param defaultString
	 * @return String[]
	 */
    protected static String[] getStringParameters(HttpServletRequest request,String paramName, String defaultString) {
		
		String[] paramValues = request.getParameterValues(paramName);
		if (paramValues == null) 
			return null;
		
		String[] values = new String[paramValues.length];
		for (int i = 0; i < paramValues.length; i++) 
			values[i] = (paramValues[i] != null )? paramValues[i] : defaultString;
			
		return values;
	}
	
	/**
	 * liyf
	 * 将表单提交的全部参数拼凑成查询条件
	 * @param req
	 * @return
	 */
    protected static String getFormQuerys(HttpServletRequest req){
		String querys = "";
		Enumeration names = req.getParameterNames();
		while(names.hasMoreElements()){
			String name = (String) names.nextElement();
			String value = req.getParameter(name);
			try {
				querys +="&"+name+"="+URLEncoder.encode(value,"UTF-8");
			} catch (UnsupportedEncodingException e) {
				e.printStackTrace();
			}
		}
		return querys;
	}
	

	/**
	 * 将请求参数保存到request中,以便在请求响应页面获取
	 * @param paramName
	 * @param request
	 */
	protected static void saveParam(String paramName,HttpServletRequest request){
		request.setAttribute(paramName, request.getParameter(paramName));
	}
}
